package goMySQL

import (
	"bytes"
	"fmt"
	"strings"
)

// Operator 操作符
// 取值:{EQ,NEQ,LT,ELT,GT,EGT}
type Operator uint

const (
	EQ  Operator = iota //EQ 等于(=)
	NEQ                 //NEQ 不等于(<>)
	LT                  //LT 小于(<)
	ELT                 //ELT 小于等于(<=)
	GT                  //GT 大于(>)
	EGT                 //EGT 大于等于(>=)
)

var operatorNames = []string{
	EQ:  "=",
	NEQ: "<>",
	LT:  "<",
	ELT: "<=",
	GT:  ">",
	EGT: ">=",
}

func (op Operator) String() string {
	if int(op) < len(operatorNames) {
		return operatorNames[op]
	}
	return ""
}

//Relation 表达式节点间关系
//取值:{NONE, And, Or}
type Relation uint

const (
	NONE Relation = iota
	And
	Or
)

func (r Relation) String() string {
	switch r {
	case And:
		return " AND "
	case Or:
		return " OR "
	}
	return ""
}

type Expr struct {
	Field string
	Op    Operator
	Value interface{}
}

func (e *Expr) String() string {
	return fmt.Sprintf("%s %s ?", e.Field, e.Op.String())
}

type ExprNode struct {
	Node     *Expr
	Relation Relation
	Next     *ExprNode
}

func (e *ExprNode) String() string {
	return e.Node.String()
}

func (e *ExprNode) Value() interface{} {
	return e.Node.Value
}

type Expression struct {
	headNode *ExprNode
}

func (e *Expression) IsEmpty() bool {
	return e.headNode == nil
}

func (e *Expression) insertNode(relation Relation, expr *Expr) {
	node := &ExprNode{
		Node:     expr,
		Relation: NONE,
		Next:     nil,
	}
	if e.IsEmpty() {
		e.headNode = node
	} else {
		cur := e.headNode
		for cur.Next != nil {
			cur = cur.Next
		}
		cur.Relation = relation
		cur.Next = node
	}
}

func (e *Expression) AddExpr(expr *Expr) {
	e.insertNode(And, expr)
}

func (e *Expression) AndExpr(field string, op Operator, value interface{}) {
	expr := &Expr{
		Field: field,
		Op:    op,
		Value: value,
	}
	e.insertNode(And, expr)
}

func (e *Expression) OrExpr(field string, op Operator, value interface{}) {
	expr := &Expr{
		Field: field,
		Op:    op,
		Value: value,
	}
	e.insertNode(Or, expr)
}

func (e *Expression) AddClause(clauses ...string) error {
	var exprs []*Expr
	for _, clause := range clauses {
		expr, err := e.parseCluase(clause)
		if err != nil {
			return err
		}
		exprs = append(exprs, expr)
	}
	for _, expr := range exprs {
		e.insertNode(And, expr)
	}
	return nil
}

func (e *Expression) AndClause(clauses ...string) error {
	var exprs []*Expr
	for _, clause := range clauses {
		expr, err := e.parseCluase(clause)
		if err != nil {
			return err
		}
		exprs = append(exprs, expr)
	}
	for _, expr := range exprs {
		e.insertNode(And, expr)
	}
	return nil
}

func (e *Expression) OrClause(clauses ...string) error {
	var exprs []*Expr
	for _, clause := range clauses {
		expr, err := e.parseCluase(clause)
		if err != nil {
			return err
		}
		exprs = append(exprs, expr)
	}
	for _, expr := range exprs {
		e.insertNode(Or, expr)
	}
	return nil
}

func (e *Expression) parseCluase(clause string) (*Expr, error) {
	var index int
	for index = 0; index < len(operatorNames); index++ {
		if strings.Index(clause, operatorNames[index]) >= 0 {
			break
		}
	}
	if index >= len(operatorNames) {
		return nil, fmt.Errorf("[%s] clause is invalid", clause)
	}
	s := strings.Split(clause, operatorNames[index])
	if len(s) != 2 {
		return nil, fmt.Errorf("[%s] clause is invalid", clause)
	}
	expr := &Expr{
		Field: strings.Trim(s[0], " "),
		Op:    Operator(index),
		Value: strings.Trim(s[1], " "),
	}
	return expr, nil
}

func (e *Expression) String() string {
	var buf bytes.Buffer
	cur := e.headNode
	for cur != nil {
		buf.WriteString(cur.String())
		if cur.Next != nil {
			buf.WriteString(cur.Relation.String())
		}
		cur = cur.Next
	}
	return buf.String()
}

func (e *Expression) Value() []interface{} {
	var values []interface{}
	cur := e.headNode
	for cur != nil {
		values = append(values, cur.Value())
		cur = cur.Next
	}
	return values
}
